/**
 * 
 */
package com.bstek.sso.handler;

import java.security.GeneralSecurityException;
import java.util.List;
import java.util.Map;

import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import javax.sql.DataSource;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.PreventedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.stereotype.Component;

import com.bstek.sso.model.UsernamePasswordSystemCodeCredential;

/**
 * @author michael
 *
 * 2017年12月12日
 */
@Component("customerQueryDatabaseAuthenticationHandler")
public class CustomerQueryDatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordSystemCodeAuthenticationHandler {
	
	   @NotNull
	   private String sql;

	   protected final HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordSystemCodeCredential credential)
	            throws GeneralSecurityException, PreventedException {  
	       if (StringUtils.isBlank(this.sql) || getJdbcTemplate() == null) {
	            throw new GeneralSecurityException("Authentication handler is not configured correctly");
	        }
	        final String username = credential.getUsername();
	        final String systemCode=credential.getSystemCode();
	        final String encryptedPassword =  this.getPasswordEncoder().encode(credential.getPassword());
	        try {
	        	Map<String, Object> object = getJdbcTemplate().queryForMap(sql, new Object[]{username});
	        	final String dbPassword=(String) object.get("password_");
	        	final String userId=(String) object.get("id_");
	  			String[] codes=systemCode.split(",");
	        	String code=codes[0];
	        	List<String> systemCodes=getSystemCodesByUsername(userId);
	        	credential.setSystemCodeList(systemCodes);
	        	if( systemCodes==null || systemCodes.isEmpty() || !systemCodes.contains(code)){
	        		throw new FailedLoginException("authentich invalid");
	        	}
	            if (!dbPassword.equals(encryptedPassword)) {
	                throw new FailedLoginException("Password does not match value on record.");
	            }
	        }
	        catch (final IncorrectResultSizeDataAccessException e) {
	            if (e.getActualSize() == 0) {
	                throw new AccountNotFoundException(username + " not found with SQL query");
	            } else {
	                throw new FailedLoginException("Multiple records found for " + username);
	            }
	        } catch (final DataAccessException e) {
	            throw new PreventedException("SQL exception while executing query for " + username, e);
	        }
	        return createHandlerResult(credential, this.principalFactory.createPrincipal(username), null);
	    }
	    /**
	     * @param sql The sql to set.
	     */
	    @Autowired
	    public void setSql(@Value("${cas.jdbc.authn.query.sql:}") final String sql) {
	        this.sql = sql;
	    }
	    @Override
	    @Autowired(required = false)
	    public void setDataSource(@Qualifier("queryDatabaseDataSource") final DataSource dataSource) {
	        super.setDataSource(dataSource);
	    }
	    public List<String> getSystemCodesByUsername(String userId) throws FailedLoginException {
	    	if(StringUtils.isBlank(userId)){
	    		throw new FailedLoginException("认证信息无效。");
	    	}
	    	String qlString="SELECT DISTINCT(ROLEINFO.SYSTEM_CODE_) "
	    			+ " FROM ROLE_INFO ROLEINFO "
	    			+ " LEFT JOIN ROLE_GRANTED_USER RGU "
	    			+ " ON ROLEINFO.ID_ = RGU.ROLE_ID_" 
	    			+ " WHERE RGU.USER_ID_=? ";
	    	List<String> systemCodes=getJdbcTemplate().queryForList(qlString, String.class,new Object[]{userId});
	    	return systemCodes;
	    }



	  
	

}
